/**
interpret
29.11.2011
RA
zatim je to hodne picate, snaha o to, aby to nejak fungovalo, postupne se budou ladit detaily
rev2 snad je to lepsi
**/


/* system */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
// #include <cmath.h>

/* local*/
#include "interpret.h"
#include "ilist.h"
#include "hash.h"



/*
int main()
{
  tIList L;
  InitIList(&L);
  AddInstruction (&L, IS_LABEL, "MAIN", NULL, NULL);
  AddInstruction (&L, IS_GENVAR, "a", NULL, NULL);
  AddInstruction (&L, IS_GENVAR, "b", NULL, NULL);
  AddInstruction (&L, IS_GENVAR, "c", NULL, NULL);
  AddInstruction (&L, IS_COPY, "\"Kurvesky dlouhy text jazyka IFJ11", NULL, "c");
  AddInstruction (&L, IS_MOV, "c", NULL, "b");
  AddInstruction (&L, IS_GENVAR, "d", NULL, NULL);
  AddInstruction (&L, IS_GENVAR, "e", NULL, NULL);
  AddInstruction (&L, IS_MOV, "b", NULL, "e");
  AddInstruction (&L, IS_WRITE, "e", NULL, NULL);


  AddInstruction (&L, IS_CALL, "fact", NULL, "hop");
  AddInstruction (&L, IS_PUSH, "e", NULL, NULL);
  AddInstruction (&L, IS_MOV, "hop", NULL, "e");
  AddInstruction (&L, IS_WRITE, "e", NULL, NULL);

  AddInstruction (&L, IS_GENVAR, "y", NULL, NULL);
  AddInstruction (&L, IS_GENVAR, "z", NULL, NULL);
  AddInstruction (&L, IS_GENVAR, "q", NULL, NULL);
  AddInstruction (&L, IS_COPY, "200", NULL, "y");
  AddInstruction (&L, IS_COPY, "300", NULL, "z");
  AddInstruction (&L, IS_ADD, "y", "z", "q");
  AddInstruction (&L, IS_WRITE, "q", NULL, NULL);

  AddInstruction (&L, IS_NOP, NULL, NULL, NULL);
  AddInstruction (&L, IS_LABEL, "fact", NULL, NULL);
  AddInstruction (&L, IS_POP, "n", NULL, NULL);
  AddInstruction (&L, IS_WRITE, "n", NULL, NULL);
  AddInstruction (&L, IS_COPY, "\"Kratsi text", NULL, "n");
  AddInstruction (&L, IS_RTN, "n", NULL, NULL);

  INTERPRET(&L);
}
*/
int gVars = 0;

char* genvarnamexpI(){
  int number = gVars++;
  char *pole= (char *)malloc(10 * sizeof(char));//osetrit
  pole[9]='\0';
  pole[0]='%';
  for(int i=8; i>0; i--)
    {
      pole[i]=(number%10)+'0';
      number=number/10;
    }
  return pole;
}


int INTERPRET(tIList *L)
{ // inicializace vsech vnitrnich seznamu
  initLCACHE(&LABLIST);
  initCACHE(&FCLIST);
  initVCACHE(&VARLIST);
  L->Act = L->First;

  //fcLabels labelTable;
  //interCache mainTable;
  //interCache endlabel = NULL;
  makeLLIST("main", &LABLIST, L);
  makeFLIST("main", &FCLIST);
  char *label = "";
  char *help = "";
  int arg=0;
  // nalezeni mainu
  GetNextInst(L, "MAIN");


  int retval = CONT;
  while(1)
  { // posun po pasce prikazu a jejich interpretace
    GetNextInst(L, label);
//     _debug_instructions(L);
    //printf("-----%s-----", L->Act->Addr1);
    /*if ( (L->Act->Instr == IS_GOTO) && (L->Act->Addr1 == NULL) )
    {
      label = L->Act->Addr3;
      printf("%s",L->Act->Addr3);
      GetNextInst(L, label);
    }*/
    label = "";
    help = "";
    arg = 0;
    //printf("....%d....%s......%s.....%s.....\n", L->Act->Instr, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3);
    switch (L->Act->Instr)
    {
      case(IS_NOP):
        IN_disposeFL(&FCLIST, &VARLIST);
        IN_disposeLL(&LABLIST);
        return 0;
        break;

      case(IS_READ):
        retval = read( &VARLIST, L->Act->Addr3, ( IN_helpread(&FCLIST, &VARLIST, L, &arg) ), arg);
	if (retval != CONT)
          return retval;
        break;

      case(IS_WRITE):
        retval = write( &VARLIST, L->Act->Addr1);
        if (retval != CONT)
          return retval;
        break;

      case(IS_ADD):
        retval = IN_add( &VARLIST, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_SUB):
        retval = IN_sub( &VARLIST, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_MUL):
        retval = IN_mul( &VARLIST, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_DIV):
        retval = IN_div( &VARLIST, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_GOTO):
	if(L->Act->Addr1 == NULL)
	  label = L->Act->Addr3;
	else
	  label = (IN_goto(&VARLIST, L->Act->Addr1, L->Act->Addr3));
        break;

      case(IS_LABEL):
        retval = makeLLIST(L->Act->Addr1, &LABLIST, L);
        if (retval != CONT)
          return retval;
        break;

      case(IS_NOT):
        retval = IN_neg(&VARLIST, L->Act->Addr1, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_COPY):
        retval = IN_MOV(L, &FCLIST, &VARLIST);
        if (retval != CONT)
          return retval;
        break;

      case(IS_LESS):
        retval = IN_less( &VARLIST, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3 );
        if (retval != CONT)
          return retval;
        break;

      case(IS_LESSEQ):
        retval = IN_lesseq( &VARLIST, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_GRT):
        retval = IN_grt ( &VARLIST, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_GRTEQ):
        retval = IN_grteq( &VARLIST, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_EQUAL):
        retval = IN_eq( &VARLIST, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_MOV):
        retval = IN_copy( &VARLIST, L->Act->Addr1, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_FIND):
        if (retval != CONT)
          return retval;
        break;

      case(IS_SORT):
        if (retval != CONT)
          return retval;
        break;

      case(IS_CONCAT):
        retval = IN_conc( &VARLIST, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_GENVAR):
        retval = IN_genvar(&FCLIST, &VARLIST, L->Act->Addr1);
        if (retval != CONT)
          return retval;
        break;

      case(IS_CALL):
	printf("Volam: %s\n", L->Act->Addr1);
        help = L->Act->Addr1;
        FCLIST.Act->retName = L->Act->Addr3;
        makeFLIST( genvarnamexpI(), &FCLIST);
        GetNextInst(L,label);
        while ( L->Act->Instr == IS_PUSH)
        {
          IN_push(&FCLIST, &VARLIST, L->Act->Addr1);
          FCLIST.Act->retLabel = L->Act;
          GetNextInst(L,label);
        }
        FCLIST.Act = FCLIST.Act->fNext;
        label = help;
        VARLIST.First = FCLIST.Act->varCache;
        VARLIST.Act = VARLIST.First;
        if (retval != CONT)
          return retval;
        break;

      case(IS_PUSH):
        if (retval != CONT)
          return retval;
        break;

      case(IS_POP):
        retval = IN_pop( &VARLIST, L->Act->Addr1);
        while ( (retval != nil) &&  (L->Act->pNext->Instr == IS_POP))
        {
          GetNextInst(L,label);
          retval = IN_pop( &VARLIST, L->Act->Addr1);
        }
        while ( L->Act->pNext->Instr == IS_POP )
          GetNextInst(L,label);

        break;

      case(IS_RTN):
        retval = IN_ret(&FCLIST, &VARLIST, L->Act->Addr1);
        if (retval != CONT)
          return retval;
	printf("Vracim se do: %s\n", FCLIST.Act->FName);
        L->Act = FCLIST.Act->retLabel;
        break;

      case(IS_POWER):
        retval = IN_POWA(&VARLIST, L->Act->Addr3, L->Act->Addr1);
        if (retval != CONT)
          return retval;
        break;

      case(IS_NEQUAL):
        retval = IN_neq( &VARLIST, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_TYPE):
        retval = IN_type( &VARLIST, L->Act->Addr1, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      case(IS_SUBSTR):
        retval = IN_substr( &VARLIST, L->Act->Addr1, L->Act->Addr2, L->Act->Addr3);
        if (retval != CONT)
          return retval;
        break;

      default:
        break;
    }
  }

  IN_disposeFL(&FCLIST, &VARLIST);
  IN_disposeLL(&LABLIST);
  printf("jsem tady\n");
  return 0;
}




void EXsearch(inIList *L, char *name)
{// vyhledavaci fce, vyhledavani poterbnych promennych
  while ( L->Act->varName != name)
  {
    if ( L->Act->varNext == NULL)
      L->Act = L->First;
    else
      L->Act = L->Act->varNext;
  }
}


int makeFLIST(char *fname, inFList *L)
{ // inicializace listu funkci
  struct intTable *T;
  if(( T = malloc( sizeof ( struct intTable ))) == NULL)
    return heaperror;
  if(L->First == NULL)
  {
    L->First = T;
    L->Act = L->First;
  }
  else
    L->Act->fNext = T;
  T->FName = fname;
  T->fNext = NULL;
  T->varCache = NULL;
  return CONT;
}

int makeLLIST(char *name, inLabels *L, tIList *P)
{ // inicializace listu labelu
  struct fcTable *T;
  if (( T = malloc( sizeof ( struct fcTable ))) == NULL)
    return heaperror;
  if ( L->First == NULL )
  {
    L->First = T;
    L->Act = L->First;
  }
  else
    L->Act->fcNext = T;
  L->Act = T;
  T->name = name;
  T->fcNext = NULL;
  T->label = P->Act;
  return CONT;
}


void initCACHE(inFList *L)
{
  L->First = NULL;
  L->Act = NULL;
}

void initVCACHE(inIList *L)
{
  L->First = NULL;
  L->Act = NULL;
}

void initLCACHE(inLabels *L)
{
  L->First = NULL;
  L->Act = NULL;
}


int IN_genvar(inFList *F, inIList *V, char *vname)
{ // generace promenne, inicializujeme na typ nil
  struct varTable *T;
  if (( T = malloc( sizeof ( struct varTable ))) == NULL )
    return heaperror;
  T->varName = vname;
  T->varNext = NULL;
  T->vartyp = varn;

  if (V->First == NULL)
  {
    V->First = T;
    V->Act = T;
    F->Act->varCache = T;
  }
  else
  {
    while (V->Act->varNext != NULL)
      V->Act = V->Act->varNext;
    V->Act->varNext = T;
    V->Act = T;
  }
  return CONT;
}


int IN_movC(inIList *L, char *name, char *val)
{ // mov stringu, na zacatku typova kontrola
  EXsearch(L, name);
  if ( L->Act->vartyp == varc || L->Act->vartyp == varn)
  {
    L->Act->charVal = val;
    L->Act->vartyp = varc;

  }
  else
    return intererror;
  return CONT;
}



int IN_movD(inIList *L, char *name, double val)
{ //viz vyse, double
  EXsearch(L, name);
  if ( L->Act->vartyp == vard || L->Act->vartyp == varn)
  {
    L->Act->intVal = val;
    L->Act->vartyp = vard;
  }
  else
    return intererror;
  return CONT;
}

int IN_movB(inIList *L, char *name, bool val)
{ // viz vyse, boolean
  EXsearch(L, name);
  if ( L->Act->vartyp == varb || L->Act->vartyp == varn)
  {
    L->Act->boolVal = val;
    L->Act->vartyp = varb;
  }
  else
    return intererror;
  return CONT;
}

int write(inIList *L, char *name)
{ // vypis na stdin, typova kontrola
  EXsearch(L, name);
  if ( L->Act->vartyp == varc)
    printf("%s\n", L->Act->charVal);
  else if ( L->Act->vartyp == vard)
    printf("%g\n", L->Act->intVal);
  else
    return intererror;
  return CONT;
}


int read(inIList *L, char *name, enumSTypes rtype, int len)
{ // nacteni ze stdin, nedodelane !!!
  EXsearch(L, name);
  L->Act->charVal = "";
  L->Act->vartyp = varn;
  char z;
  double y;
  switch(rtype)
  {
    case DOUBLE:
      scanf("%lf", &y);
      if (y < 0)
        return intererror;
      L->Act->intVal = y;
      L->Act->vartyp = vard;
      break;

    case STRING_EOF:
      L->Act->vartyp = varc;
      while (( z = getchar()) != EOF)
        IN_addchar(L, (L->Act->charVal), &z);
      break;

    case STRING_ENDOFLINE:
      L->Act->vartyp = varc;
      while (( z = getchar()) != '\n')
        IN_addchar(L, (L->Act->charVal), &z);
      break;

    case STRING_LEN:
      L->Act->vartyp = varc;
      while ( len != 0 )
      {
         z = getchar();
         IN_addchar(L, (L->Act->charVal), &z);
         len--;
      }
      break;

    default:
      break;
  }
  return CONT;
}



int IN_add(inIList *L, char *IN_NUM1, char *IN_NUM2, char *OUT)
{ // operace +
  double t1, t2;
  EXsearch(L, IN_NUM1);
  if ( L->Act->vartyp != vard )
    return intererror;
  t1 = L->Act->intVal;

  EXsearch(L, IN_NUM2);
  if ( L->Act->vartyp != vard )
    return intererror;
  t2 = L->Act->intVal;

  IN_movD(L, OUT, ( t1 + t2 ));
  return CONT;
}


int IN_sub(inIList *L, char *IN_NUM1, char *IN_NUM2, char *OUT)
{ // -
  double t1, t2;
  EXsearch(L, IN_NUM1);
  if ( L->Act->vartyp != vard )
    return intererror;
  t1 = L->Act->intVal;

  EXsearch(L, IN_NUM2);
  if ( L->Act->vartyp != vard )
    return intererror;
  t2 = L->Act->intVal;


  IN_movD(L, OUT, ( t1 - t2 ));
  return CONT;
}


int IN_mul(inIList *L, char *IN_NUM1, char *IN_NUM2, char *OUT)
{ // *
  double t1, t2;
  EXsearch(L, IN_NUM1);
  if ( L->Act->vartyp != vard )
    return intererror;
  t1 = L->Act->intVal;

  EXsearch(L, IN_NUM2);
  if ( L->Act->vartyp != vard )
    return intererror;
  t2 = L->Act->intVal;

  IN_movD(L, OUT, ( t1 * t2 ));
  return CONT;
}


int IN_div(inIList *L, char *IN_NUM1, char *IN_NUM2, char *OUT)
{ // /
  double t1, t2;
  EXsearch(L, IN_NUM1);
  if ( L->Act->vartyp != vard )
    return intererror;
  t1 = L->Act->intVal;

  EXsearch(L, IN_NUM2);
  if ( L->Act->vartyp != vard )
    return intererror;
  t2 = L->Act->intVal;
  if ( t2 == 0)
    return intererror;

  IN_movD(L, OUT, ( t1 / t2 ));
  return CONT;
}


int IN_neg(inIList *L, char *EI, char *EO)
{ // neagace s typovou kontrolou
  EXsearch(L, EI);
  if ( L->Act->vartyp != varb )
    return intererror;
  if( L->Act->boolVal != 0)
    IN_movB(L, EO, 0);
  else
    IN_movB(L, EO, 1);

  return CONT;
}


int IN_less(inIList *L, char *in0, char *in1, char *out)
{ // < na zacatku typova kontrola podle toho pokracuje k doublum, nebo stringum
  double t0, t1;
  char *s0, *s1;


  EXsearch(L, in0);
  switch(L->Act->vartyp)
  {
    case(vard):
      t0 = L->Act->intVal;
      EXsearch(L, in1);
      if ( L->Act->vartyp != vard )
        return intererror;
      t1 = L->Act->intVal;
      IN_movB(L, out, ((t0 < t1) ? 1 : 0));
      break;

    case(varc):
      s0 = L->Act->charVal;
      EXsearch(L, in1);
      if ( L->Act->vartyp == varc )
        return intererror;
      s1 = L->Act->charVal;
      IN_movB(L, out, (strcmp (s0, s1) < 0 ? 1 : 0));
      break;

    default:
      break;
  }
  return CONT;
}

int IN_lesseq(inIList *L, char *in0, char *in1, char *out)
{ // <=
  double t0, t1;
  char *s0, *s1;


  EXsearch(L, in0);
  switch(L->Act->vartyp)
  {
    case(vard):
      t0 = L->Act->intVal;
      EXsearch(L, in1);
      if ( L->Act->vartyp != vard )
        return intererror;
      t1 = L->Act->intVal;
      IN_movB(L, out, ((t0 <= t1) ? 1 : 0));
      break;

    case(varc):
      s0 = L->Act->charVal;
      EXsearch(L, in1);
      if ( L->Act->vartyp == varc )
        return intererror;
      s1 = L->Act->charVal;
      IN_movB(L, out, (strcmp (s0, s1) <= 0 ? 1 : 0));
      break;

    default:
      break;
  }
  return CONT;
}


int IN_grt(inIList *L, char *in0, char *in1, char *out)
{ // >
  double t0, t1;
  char *s0, *s1;

  EXsearch(L, in0);
  switch(L->Act->vartyp)
  {
    case(vard):
      t0 = L->Act->intVal;
      EXsearch(L, in1);
      if ( L->Act->vartyp != vard )
        return intererror;
      t1 = L->Act->intVal;
      IN_movB(L, out, ((t0 > t1) ? 1 : 0));
      break;

    case(varc):
      s0 = L->Act->charVal;
      EXsearch(L, in1);
      if ( L->Act->vartyp == varc )
        return intererror;
      s1 = L->Act->charVal;
      IN_movB(L, out, (strcmp (s0, s1) > 0 ? 1 : 0));
      break;

    default:
      break;
  }
  return CONT;
}

int IN_grteq(inIList *L, char *in0, char *in1, char *out)
{ // >=
  double t0, t1;
  char *s0, *s1;

  EXsearch(L, in0);
  switch(L->Act->vartyp)
  {
    case(vard):
      t0 = L->Act->intVal;
      EXsearch(L, in1);
      if ( L->Act->vartyp != vard )
        return intererror;
      t1 = L->Act->intVal;
      IN_movB(L, out, ((t0 >= t1) ? 1 : 0));
      break;

    case(varc):
      s0 = L->Act->charVal;
      EXsearch(L, in1);
      if ( L->Act->vartyp == varc )
        return intererror;
      s1 = L->Act->charVal;
      IN_movB(L, out, (strcmp (s0, s1) >= 0 ? 1 : 0));
      break;

    default:
      break;
  }
  return CONT;
}

int IN_conc(inIList *L, char *s0, char *s1, char *out)
{ // konkatenace dvou stringu, melo by fungovat pro nekonecne dlouho stringy
  char *t0;
  char *t1;
  EXsearch(L, s0);
  if ( L->Act->vartyp !=  varc)
    return intererror;
  t0 = L->Act->charVal;

  EXsearch(L, s1);
  if ( L->Act->vartyp != varc )
    return intererror;

  t1 = L->Act->charVal;
  EXsearch(L, out);
  IN_addchar(L, t0, t1);
  return CONT;
}

int IN_addchar(inIList *L, char *s0, char *s1)
{ // funkce pro realokaci
  int t0, t1;
  if(( L->Act->vartyp != varc ) && ( L->Act->vartyp != varn ))
    return intererror;
  L->Act->vartyp = varc;
  t0 = strlen(s0);
  t1 = strlen(s1);
  if ((*L->Act->charVal = malloc ((t0+t1+1) * sizeof(char)) == NULL))
    return heaperror;
  strcpy (L->Act->charVal, s0);
  strcat ( L->Act->charVal, s1 );
  return CONT;
}


int IN_eq(inIList *L, char *in0, char *in1, char *out)
{ // ==
  double t0, t1;
  char *s0, *s1;

  EXsearch(L, in0);
  switch(L->Act->vartyp)
  {
    case(vard):
      t0 = L->Act->intVal;
      EXsearch(L, in1);
      if ( L->Act->vartyp != vard )
        return intererror;
      t1 = L->Act->intVal;
      IN_movB(L, out, ((t0 == t1) ? 1 : 0));
      break;

    case(varc):
      s0 = L->Act->charVal;
      EXsearch(L, in1);
      if ( L->Act->vartyp == varc )
        return intererror;
      s1 = L->Act->charVal;
      IN_movB(L, out, (strcmp (s0, s1) == 0 ? 1 : 0));
      break;

    default:
      break;
  }
  return CONT;
}

int IN_neq(inIList *L, char *in0, char *in1, char *out)
{ // !=
  double t0, t1;
  char *s0, *s1;


  EXsearch(L, in0);
  switch(L->Act->vartyp)
  {
    case(vard):
      t0 = L->Act->intVal;
      EXsearch(L, in1);
      if ( L->Act->vartyp != vard )
        return intererror;
      t1 = L->Act->intVal;
      IN_movB(L, out, ((t0 != t1) ? 1 : 0));
      break;

    case(varc):
      s0 = L->Act->charVal;
      EXsearch(L, in1);
      if ( L->Act->vartyp == varc )
        return intererror;
      s1 = L->Act->charVal;
      IN_movB(L, out, (strcmp (s0, s1) != 0 ? 1 : 0));
      break;

    default:
      break;
  }
  return CONT;
}


int IN_type(inIList *L, char *name, char *out)
{ // typova kontrola, ktera vraci string s nazvem
  EXsearch(L, name);
  switch (L->Act->vartyp)
  {
    case vard:
      IN_movC(L, out, "number" );
      break;

    case varc:
      IN_movC(L, out, "string");
      break;

    case varb:
      IN_movC(L, out, "boolean");
      break;

    case varn:
      IN_movC(L, out, "nil");
      break;

    default:
      break;
  }
  return CONT;
}


int IN_substr(inIList *L, char *in0, char *in1, char *name)
{ // substring, vyuzivajici knihovni fci jazyka C, pouze musim poupravit vstupni cisilka a je to :>
  int start, final;
  EXsearch(L, in0);
  if(L->Act->vartyp != vard)
    return intererror;
  start = L->Act->intVal;

  EXsearch(L, in1);
  if(L->Act->vartyp != vard)
    return intererror;
  final = L->Act->intVal;

  if ( start == 0 )
    return intererror;

  EXsearch(L, name);
  if( start < 0 )
    start = (strlen(L->Act->charVal)) + start;
  else
    start = start - 1;
  if ( final++ < 0 )
    final = ( strlen (L->Act->charVal)) + final;
  final = final - start;
  if ( final < 0 )
      final = 0;

  char *temp;
  if (( temp = malloc( final * sizeof(char) )) == NULL)
      return heaperror;
  strncpy(temp, L->Act->charVal + start, final);
  temp[ final ] = '\0';
  EXsearch(L, name);
  IN_movC(L, name, temp);
  return CONT;
}


int IN_POWA(inIList *L, char *name, char *powr)
{ // mocnina
  double temp;
  EXsearch(L, powr);
  temp = L->Act->intVal;
  EXsearch(L, name);
//   temp = pow(L->Act->intVal, temp);
  IN_movD(L, name, temp);
  return CONT;
}


int IN_disposeIL(inIList *L)
{ // zruseni listu promennych
  L->Act = NULL;
  struct varTable *temp;
  while(L->First->varNext != NULL)
  {
    temp = L->First;
    L->First=L->First->varNext;
    free(temp);
  }
  return 0;
}

int IN_disposeFL(inFList *L, inIList *T)
{ // zruseni listu promennych
  L->Act = NULL;
  struct intTable *temp;
  while(L->First->fNext != NULL)
  {
    IN_disposeIL(T);
    temp = L->First;
    L->First=L->First->fNext;
    free(temp);
  }
  return 0;
}

int IN_disposeLL(inLabels *L)
{ // zruseni listu promennych
  L->Act = NULL;
  struct fcTable *temp;
  while(L->First->fcNext != NULL)
  {
    temp = L->First;
    L->First=L->First->fcNext;
    free(temp);
  }
  return 0;
}


int IN_ret(inFList *F, inIList *L, char *name)
{ // return dane promenne + zruseni funkce, ze ktere return vychazi, pokud jde z mainu vraci 0 = uspesna interpretace
  double td;
  char *tc;
  bool tb;
  char *n = "";

  EXsearch(L, name);
  switch ( L->Act->vartyp )
  {
    case vard:
      td = L->Act->intVal;
      IN_disfnc( F, L, F->Act->FName);
      L->First = F->Act->varCache;
      L->Act = L->First;
      n = F->Act->retName;
      if ( strcmp ( n, "main") == 0 )
        return 0;
      IN_movD( L, n, td);
      break;

    case varc:
      tc = L->Act->charVal;
      IN_disfnc( F, L, F->Act->FName);
      L->First = F->Act->varCache;
      L->Act = L->First;
      n = F->Act->retName;
      if ( strcmp ( n, "main") == 0 )
        return 0;
      IN_movC( L, n, tc);
      break;

    case varb:
      tb = L->Act->boolVal;
      IN_disfnc( F, L, F->Act->FName);
      L->First = F->Act->varCache;
      L->Act = L->First;
      n = F->Act->retName;
      if ( strcmp ( n, "main") == 0 )
        return 0;
      IN_movB( L, n, tb);
      break;

    default:
      break;
  }
  return CONT;
}


int IN_disfnc(inFList *F, inIList *L, char *n)
{ // fce na zruseni prvku seznamu s returnovanou fci
  IN_disposeIL(L);
  if ( F->Act->fNext == NULL)
      F->Act = F->First;

  while ( F->Act->fNext->FName != n)
  {
    if ( F->Act->fNext == NULL)
      F->Act = F->First;
    else
      F->Act = F->Act->fNext;
  }
  initVCACHE(L);
  L->First = F->Act->varCache;
  L->Act = L->First;
  free(F->Act->fNext);
  F->Act->fNext = NULL;

  return CONT;
}


char *IN_goto(inIList *L, char *name, char *label)
{ // goto label
  char *temp = "";
  EXsearch( L, name);
  return (( L->Act->boolVal == true) ? label : temp);
}


enumSTypes IN_helpread(inFList *F, inIList *L,tIList *T, int *len)
{
  char z;
  int c = 1;
  z = T->Act->Addr1[c];
  c++;
  if ( z == '*')
  {
    z = T->Act->Addr1[c];
    if ( z == 'a')
      return STRING_EOF;
    else if ( z == 'n')
      return DOUBLE;
    else if ( z == 'l')
      return STRING_ENDOFLINE;
  }
  else
  {
    char *name = "%rhelp";
    IN_genvar(F, L, name);
    IN_movC( L, name, &z);
    EXsearch(L, name);
    while(( z = T->Act->Addr1[c] ) != '\0')
    {
      IN_addchar(L, L->Act->charVal, &z);
      c++;
    }
    *len = atoi(L->Act->charVal);
    return STRING_LEN;
  }
  return CONT;
}

int IN_MOV(tIList *T, inFList *F, inIList *L)
{
  char z;
  int c = 0;

  z = T->Act->Addr1[c];
  if( z == '"')
  {
    char *name = "%mhelp";
    IN_genvar(F, L, name);
    IN_movC( L, name, T->Act->Addr1);
    
    c = strlen(T->Act->Addr1);
//     printf("____c: %d _______%s______________ %d\n",c, T->Act->Addr1, T->Act->Addr1);
    char *temp;
    if (( temp = malloc( (c + 1) * sizeof(char) )) == NULL)
      return heaperror;
    strncpy( temp, T->Act->Addr1 + 1, c - 1);
    temp[ c ] = '\0';
    EXsearch(L, name);
    IN_movC(L, name, temp);

    if ( (strcmp ( L->Act->charVal, "true")) == 0 )
      IN_movB( L, T->Act->Addr3, true);
    else
    {
      if((strcmp ( L->Act->charVal, "false")) == 0 )
        IN_movB( L, T->Act->Addr3, false);
      else
        IN_movC( L, T->Act->Addr3, L->Act->charVal);
    }
  }
  else
    IN_movD(L, T->Act->Addr3, atof( T->Act->Addr1));


  return CONT;
}

int IN_push(inFList *F, inIList *L, char *name)
{
  char *nam;
  double dval;
  char *cval;
  bool bval;
  if (( nam = malloc(( strlen(L->Act->varName) + 3 )* sizeof(char))) == NULL)
    return heaperror;
  strcpy(nam, "%");
  EXsearch(L,name);
  strcat(nam, name);
  switch(L->Act->vartyp)
  {
    case(vard):
      dval = L->Act->intVal;
      F->Act = F->Act->fNext;
      L->First = F->Act->varCache;
      L->Act = L->First;
      IN_genvar( F, L, nam);
      IN_movD(L, nam, dval);
      break;
    case(varc):
      cval = L->Act->charVal;
      F->Act = F->Act->fNext;
      L->First = F->Act->varCache;
      L->Act = L->First;
      IN_genvar( F, L, nam);
      IN_movC(L, nam, cval);
      break;
    case(varb):
      bval = L->Act->boolVal;
      F->Act = F->Act->fNext;
      L->First = F->Act->varCache;
      L->Act = L->First;
      IN_genvar( F, L, nam);
      IN_movB(L, nam, bval);
      break;
    default:
      break;
  }
  cval = F->Act->FName;
  F->Act = F->First;
  while ( F->Act->fNext->FName != cval)
    F->Act = F->Act->fNext;
  L->First = F->Act->varCache;
  L->Act = L->First;
  free(nam);
  return CONT;
}

int IN_pop(inIList *L, char *name)
{
  L->Act->varName = name;
  if (L->Act->varNext != NULL)
  {
    L->Act = L->Act->varNext;
    return CONT;
  }
  else
    return nil;
}


int IN_copy(inIList *L, char *in, char *out)
{
  VType Ttemp;
  char* Ctemp;
  double Dtemp;
  bool Btemp;
  EXsearch(L, in);
  Ttemp = L->Act->vartyp;

  switch(Ttemp)
  {
    case(varc):
      Ctemp = L->Act->charVal;
      EXsearch(L, out);
      if ( (L->Act->vartyp != varc) && (L->Act->vartyp != varn) )
        return intererror;
      L->Act->charVal = Ctemp;
      L->Act->vartyp = varc;
      break;

    case(vard):
      Dtemp = L->Act->intVal;
      EXsearch(L, out);
      if ( (L->Act->vartyp != vard) && (L->Act->vartyp != varn) )
        return intererror;
      L->Act->intVal = Dtemp;
      L->Act->vartyp = vard;
      break;

    case(varb):
      Btemp = L->Act->boolVal;
      EXsearch(L, out);
      if ( (L->Act->vartyp != varb) && (L->Act->vartyp != varn) )
        return intererror;
      L->Act->boolVal = Btemp;
      L->Act->vartyp = varb;
      break;

    default:
      break;
  }

  return CONT;
}
